package com.biodiv.miracle.web.servlet;

import com.biodiv.miracle.ioc.context.ApplicationContext;
import com.biodiv.miracle.ioc.aware.ApplicationContextAware;
import com.biodiv.miracle.web.support.annotation.Controller;
import com.biodiv.miracle.web.support.annotation.RequestMapping;
import com.biodiv.miracle.web.handler.HandlerMethod;
import com.biodiv.miracle.web.handler.MappingObject;
import com.biodiv.miracle.web.interceptor.WebMvcConfigurer;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author: tianquan
 * @date: 2025-05-25  21:04
 * @description: 模版父类
 */
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

    private static final Log logger = LogFactory.getLog(FrameworkServlet.class);
    protected ApplicationContext applicationContext;
    private boolean initialized = false;

    @Override
    public void init() {
        if (initialized){
            return;
        }
        //  获取所有Controller类的方法映射
        parseRequestMapping();
        // 添加拦截器
        addInterceptor();
        initialized = true;
    }

    private void addInterceptor() {
        // 获取自定义的WebMvcConfigurer
        List<WebMvcConfigurer> mvcConfigurers = applicationContext.getBeans(WebMvcConfigurer.class);
        if (mvcConfigurers != null && mvcConfigurers.size() > 1){
            throw new RuntimeException("Multiple WebMvcConfigurer");
        }
        if (mvcConfigurers != null && mvcConfigurers.size() == 1){
            // 下发给用户添加自定义拦截器
            mvcConfigurers.get(0).addInterceptors(getInterceptorRegistry());
        }
    }

    private void parseRequestMapping() {
        // 扫描所有Controller类
        List<Object> controllerBeans = applicationContext.getBeanByAnnotation(Controller.class);
        // 解析@RequestMapping注解
        for (Object controllerBean : controllerBeans) {
            String basePath = "";
            RequestMapping baseRequestMapping = controllerBean.getClass().getAnnotation(RequestMapping.class);
            if (baseRequestMapping != null) {
                basePath = baseRequestMapping.path();
                String value = baseRequestMapping.value();
                if (value != null && !value.isEmpty()) {
                    basePath = value;
                }
            }
            Method[] methods = controllerBean.getClass().getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                if (requestMapping == null) {
                    continue;
                }
                String value = requestMapping.value();
                String path = requestMapping.path();
                if (value !=  null && !value.isEmpty()){
                    path = value;
                }
                String requestMethod = requestMapping.method().name();
                String url = basePath + path;
                MappingObject mappingObject = addRequestMapping(requestMethod, url);
                HandlerMethod handlerMethod = new HandlerMethod(controllerBean, method, method.getParameters());
                addHandlerMethod(mappingObject, handlerMethod);
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) {
        doService(request, response);
    }

    protected abstract void doService(HttpServletRequest request, HttpServletResponse response);

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) {
        String method = request.getMethod();
        if (method != null && !"PATCH".equals(method)) {
            try {
                super.service(request, response);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            this.processRequest(request, response);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        this.processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        this.processRequest(request, response);
    }

    @Override
    protected void doPut(HttpServletRequest request, HttpServletResponse response){
        this.processRequest(request, response);
    }

    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) {
        this.processRequest(request, response);
    }

    @Override
    protected void doOptions(HttpServletRequest request, HttpServletResponse response) {
        this.processRequest(request, response);
    }

    @Override
    protected void doTrace(HttpServletRequest request, HttpServletResponse response){
        this.processRequest(request, response);
    }

}
